When an OPC UA Alarms & Conditions server generates an event, the EasyUAClient object generates an EventNotification event. For subscription mechanism to be useful, you should hook one or more event handlers to this event. This event is raised for every event generated by a subscribed OPC monitored item.
To be more precise, the EventNotification event is actually generated in other cases, too - if there is any significant occurrence related to the event subscription. This can be for three reasons:
The notification for the EventNotification event contains an EasyUAEventNotificationEventArgs argument. You will find all kind of relevant data in this object. Some properties in this object contain valid information under all circumstances - e.g. Arguments (including Arguments.State). Other properties, such as EventData, contain null references when there is no associated information for them. When the EventData property is not a null reference, it contains a UAEventData object describing the detail of the actual OPC event received from the OPC UA Alarms & Conditions server.
Before further processing, your code should always inspect the value of Exception property of the event arguments. If this property is not a null reference, there has been an error related to the event subscription, the Exception property contains information about the problem, and the EventData property does not contain a valid object.
If the Exception property is a null reference, the notification may be informing you about the fact that a condition refresh is being initiated or is complete (in this case, the RefreshInitiated or RefreshComplete property is 'true'), or that an event subscription has been successfully connected or re-connected (in this case, the EventData property is a null reference). If none of the previous applies, the EventData property contains a valid UAEventData object with details about the actual OPC event generated by the OPC server.
Pseudo-code for the full EventNotification event handler may look similar to this:
if notificationEventArgs.Exception is not null then
An error occurred and the subscription is disconnected, handle it (or ignore)
else if notificationEventArgs.RefreshInitiated then
A “refresh” has been initiated; handle it
else if notificationEventArgs.RefreshComplete then
A “refresh” is complete; handle it
else if notificationEventArgs.EventData is null then
Subscription has been successfully connected or re-connected, handle it (or ignore)
else
Handle the OPC event, details are in notificationEventArgs.EventData. You may use notificationEventArgs.Refresh flag for distinguishing refreshes from original notifications.
The EventNotification event handler is called on a thread determined by the EasyUAClient component. For details, please refer to “Multithreading and Synchronization” chapter under “Advanced Topics”.
The arguments of each event notification (EasyUAEventNotificationEventArgs) have an EventData property (of type UAEventData, described further below), which contains details about the OPC UA event. In addition, common information such as the copy of the input arguments to the subscription, i.e. identification of the endpoint and node (monitored item) which has generated the event, is included. The Exception property (and several related properties) indicates success (when it is a null reference), or a failure (in which case it contains an exception object describing the error).
The UAEventData object contains details about an OPC UA event, i.e. the information that the OPC UA server sends with the event notification. Primarily, it has a FieldResults property, which is a dictionary containing results for each of the fields in the select clauses of the event filter. Each field results is a ValueResult object, i.e. it can either contain the actual value, or an error indication.
// This example shows how to display all fields of incoming events, or extract specific fields. // // Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html . using System; using System.Collections.Generic; using OpcLabs.BaseLib.OperationModel; using OpcLabs.EasyOpc.UA; using OpcLabs.EasyOpc.UA.AddressSpace.Standard; using OpcLabs.EasyOpc.UA.AlarmsAndConditions; using OpcLabs.EasyOpc.UA.Filtering; using OpcLabs.EasyOpc.UA.OperationModel; namespace UADocExamples.AlarmsAndConditions { class FieldResults { public static void Main1() { UAEndpointDescriptor endpointDescriptor = "opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer"; // Instantiate the client object and hook events. var client = new EasyUAClient(); client.EventNotification += client_EventNotification; Console.WriteLine("Subscribing..."); client.SubscribeEvent(endpointDescriptor, UAObjectIds.Server, 1000); Console.WriteLine("Processing event notifications for 30 seconds..."); System.Threading.Thread.Sleep(30 * 1000); Console.WriteLine("Unsubscribing..."); client.UnsubscribeAllMonitoredItems(); Console.WriteLine("Waiting for 5 seconds..."); System.Threading.Thread.Sleep(5 * 1000); Console.WriteLine("Finished."); } static void client_EventNotification(object sender, EasyUAEventNotificationEventArgs e) { Console.WriteLine(); // Display the event. if (e.EventData is null) { Console.WriteLine(e); return; } Console.WriteLine("All fields:"); foreach (KeyValuePair<UAAttributeField, ValueResult> pair in e.EventData.FieldResults) { UAAttributeField attributeField = pair.Key; ValueResult valueResult = pair.Value; Console.WriteLine(" {0} -> {1}", attributeField, valueResult); } // Extracting a specific field using a standard operand symbol. Console.WriteLine($"Source name: {e.EventData.FieldResults[UABaseEventObject.Operands.SourceName]}"); // Extracting a specific field using an event type ID and a simple relative path. Console.WriteLine( $"Message: {e.EventData.FieldResults[UAFilterElements.SimpleAttribute(UAObjectTypeIds.BaseEventType, "/Message")]}"); } // Example output (truncated): //Subscribing... //Processing event notifications for 30 seconds... // //[] Success // //[] Success; Refresh; RefreshInitiated // //All fields: // NodeId="BaseEventType", NodeId -> Success; nsu=http://opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank?OnlineState {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/EventId -> Success; [16] {95, 68, 22, 205, 114, ...} {System.Byte[]} // NodeId="BaseEventType"/EventType -> Success; DialogConditionType {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/SourceNode -> Success; nsu=http://opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/SourceName -> Success; EastTank {System.String} // NodeId="BaseEventType"/Time -> Success; 9/10/2019 8:08:23 PM {System.DateTime} // NodeId="BaseEventType"/ReceiveTime -> Success; 9/10/2019 8:08:23 PM {System.DateTime} // NodeId="BaseEventType"/LocalTime -> Success; 00:00, DST {OpcLabs.EasyOpc.UA.UATimeZoneData} // NodeId="BaseEventType"/Message -> Success; The dialog was activated {System.String} // NodeId="BaseEventType"/Severity -> Success; 100 {System.Int32} //Source name: Success; EastTank {System.String} //Message: Success; The dialog was activated {System.String} // //All fields: // NodeId="BaseEventType", NodeId -> Success; nsu=http://opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank?Red {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/EventId -> Success; [16] {124, 156, 219, 54, 120, ...} {System.Byte[]} // NodeId="BaseEventType"/EventType -> Success; ExclusiveDeviationAlarmType {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/SourceNode -> Success; nsu=http://opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/SourceName -> Success; EastTank {System.String} // NodeId="BaseEventType"/Time -> Success; 10/14/2019 4:00:13 PM {System.DateTime} // NodeId="BaseEventType"/ReceiveTime -> Success; 10/14/2019 4:00:13 PM {System.DateTime} // NodeId="BaseEventType"/LocalTime -> Success; 00:00, DST {OpcLabs.EasyOpc.UA.UATimeZoneData} // NodeId="BaseEventType"/Message -> Success; The alarm was acknoweledged. {System.String} // NodeId="BaseEventType"/Severity -> Success; 500 {System.Int32} //Source name: Success; EastTank {System.String} //Message: Success; The alarm was acknoweledged. {System.String} // //... } }
# This example shows how to display all fields of incoming events, or extract specific fields. # # Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html . #requires -Version 5.1 using namespace OpcLabs.BaseLib.OperationModel using namespace OpcLabs.EasyOpc.UA using namespace OpcLabs.EasyOpc.UA.AddressSpace using namespace OpcLabs.EasyOpc.UA.AddressSpace.Standard using namespace OpcLabs.EasyOpc.UA.AlarmsAndConditions using namespace OpcLabs.EasyOpc.UA.Filtering # The path below assumes that the current directory is [ProductDir]/Examples-NET/PowerShell/Windows . Add-Type -Path "../../../Components/Opclabs.QuickOpc/net472/OpcLabs.EasyOpcUA.dll" Add-Type -Path "../../../Components/Opclabs.QuickOpc/net472/OpcLabs.EasyOpcUAComponents.dll" # Define which server we will work with. [UAEndpointDescriptor]$endpointDescriptor = "opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer" # Instantiate the client object. $client = New-Object EasyUAClient # Event notification handler Register-ObjectEvent -InputObject $client -EventName EventNotification -Action { Write-Host # Display the event. if ($EventArgs.EventData -eq $null) { Write-Host $EventArgs return } Write-Host "All fields:" foreach ($pair in $EventArgs.EventData.FieldResults.GetEnumerator()) { [UAAttributeField]$attributeField = $pair.Key [ValueResult]$valueResult = $pair.Value Write-Host " $($attributeField) -> $($valueResult)" } # Extracting a specific field using a standard operand symbol. Write-Host "Source name: $($EventArgs.EventData.FieldResults[[UABaseEventObject+Operands]::SourceName])" # Extracting a specific field using an event type ID and a simple relative path. Write-Host ` "Message: $($EventArgs.EventData.FieldResults[[UAFilterElements]::SimpleAttribute([UAObjectTypeIds]::BaseEventType, "/Message")])" } Write-Host "Subscribing..." [IEasyUAClientExtension]::SubscribeEvent($client, $endpointDescriptor, [UAObjectIds]::Server, 1000) Write-Host "Processing event notifications for 30 seconds..." $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() while ($stopwatch.Elapsed.TotalSeconds -lt 30) { Start-Sleep -Seconds 1 } Write-Host "Unsubscribing..." $client.UnsubscribeAllMonitoredItems() Write-Host "Waiting for 5 seconds..." Start-Sleep -Seconds 5 Write-Host "Finished." # Example output (truncated): #Subscribing... #Processing event notifications for 30 seconds... # #[] Success # #[] Success; Refresh; RefreshInitiated # #All fields: # NodeId="BaseEventType", NodeId -> Success; nsu=http:#opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank?OnlineState {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} # NodeId="BaseEventType"/EventId -> Success; [16] {95, 68, 22, 205, 114, ...} {System.Byte[]} # NodeId="BaseEventType"/EventType -> Success; DialogConditionType {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} # NodeId="BaseEventType"/SourceNode -> Success; nsu=http:#opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} # NodeId="BaseEventType"/SourceName -> Success; EastTank {System.String} # NodeId="BaseEventType"/Time -> Success; 9/10/2019 8:08:23 PM {System.DateTime} # NodeId="BaseEventType"/ReceiveTime -> Success; 9/10/2019 8:08:23 PM {System.DateTime} # NodeId="BaseEventType"/LocalTime -> Success; 00:00, DST {OpcLabs.EasyOpc.UA.UATimeZoneData} # NodeId="BaseEventType"/Message -> Success; The dialog was activated {System.String} # NodeId="BaseEventType"/Severity -> Success; 100 {System.Int32} #Source name: Success; EastTank {System.String} #Message: Success; The dialog was activated {System.String} # #All fields: # NodeId="BaseEventType", NodeId -> Success; nsu=http:#opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank?Red {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} # NodeId="BaseEventType"/EventId -> Success; [16] {124, 156, 219, 54, 120, ...} {System.Byte[]} # NodeId="BaseEventType"/EventType -> Success; ExclusiveDeviationAlarmType {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} # NodeId="BaseEventType"/SourceNode -> Success; nsu=http:#opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} # NodeId="BaseEventType"/SourceName -> Success; EastTank {System.String} # NodeId="BaseEventType"/Time -> Success; 10/14/2019 4:00:13 PM {System.DateTime} # NodeId="BaseEventType"/ReceiveTime -> Success; 10/14/2019 4:00:13 PM {System.DateTime} # NodeId="BaseEventType"/LocalTime -> Success; 00:00, DST {OpcLabs.EasyOpc.UA.UATimeZoneData} # NodeId="BaseEventType"/Message -> Success; The alarm was acknoweledged. {System.String} # NodeId="BaseEventType"/Severity -> Success; 500 {System.Int32} #Source name: Success; EastTank {System.String} #Message: Success; The alarm was acknoweledged. {System.String} # #...
# This example shows how to display all fields of incoming events, or extract specific fields. # # Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html . # OPC client and subscriber examples in Python on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-Python . # The QuickOPC package is needed. Install it using "pip install opclabs_quickopc". import opclabs_quickopc import time # Import .NET namespaces. from OpcLabs.EasyOpc.UA import * from OpcLabs.EasyOpc.UA.AddressSpace.Standard import * from OpcLabs.EasyOpc.UA.AlarmsAndConditions import * from OpcLabs.EasyOpc.UA.Filtering import * from OpcLabs.EasyOpc.UA.OperationModel import * def eventNotification(sender, eventArgs): print() # Display the event. if eventArgs.EventData is None: print(eventArgs) return print('All fields:') for pair in eventArgs.EventData.FieldResults: attributeField = pair.Key valueResult = pair.Value print(' ', attributeField, ' -> ', valueResult, sep='') # Extracting a specific field using a standard operand symbol. print('Source name: ', eventArgs.EventData.FieldResults.get_Item(UAAttributeField(UABaseEventObject.Operands.SourceName)), sep='') # Extracting a specific field using an event type ID and a simple relative path. print('Message: ', eventArgs.EventData.FieldResults.get_Item(UAAttributeField( UAFilterElements.SimpleAttribute(UANodeDescriptor(UAObjectTypeIds.BaseEventType), '/Message'))), sep='') # Define which server we will work with. endpointDescriptor = UAEndpointDescriptor('opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer') # Instantiate the client object and hook events. client = EasyUAClient() client.EventNotification += eventNotification print('Subscribing...') IEasyUAClientExtension.SubscribeEvent( client, endpointDescriptor, UANodeDescriptor(UAObjectIds.Server), 1000) print('Processing event notifications for 30 seconds...') time.sleep(30) print() print('Unsubscribing...') client.UnsubscribeAllMonitoredItems() print('Waiting for 5 seconds...') time.sleep(5) print('Finished.')
' This example shows how to display all fields of incoming events, or extract specific fields. ' ' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html . Imports OpcLabs.EasyOpc.UA Imports OpcLabs.EasyOpc.UA.AddressSpace.Standard Imports OpcLabs.EasyOpc.UA.AlarmsAndConditions Imports OpcLabs.EasyOpc.UA.Filtering Imports OpcLabs.EasyOpc.UA.OperationModel Namespace AlarmsAndConditions Friend Class FieldResults Public Shared Sub Main1() ' Instantiate the client object and hook events Dim client = New EasyUAClient() AddHandler client.EventNotification, AddressOf client_EventNotification Console.WriteLine("Subscribing...") client.SubscribeEvent( _ "opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer", _ UAObjectIds.Server, _ 1000) Console.WriteLine("Processing event notifications for 30 seconds...") Threading.Thread.Sleep(30 * 1000) Console.WriteLine("Unsubscribing...") client.UnsubscribeAllMonitoredItems() Console.WriteLine("Waiting for 5 seconds...") Threading.Thread.Sleep(5 * 1000) End Sub Private Shared Sub client_EventNotification(ByVal sender As Object, ByVal e As EasyUAEventNotificationEventArgs) Console.WriteLine() ' Display the event If e.EventData Is Nothing Then Console.WriteLine(e) Exit Sub End If Console.WriteLine("All fields:") For Each pair In e.EventData.FieldResults Dim attributeField = pair.Key Dim valueResult = pair.Value Console.WriteLine(" {0} -> {1}", attributeField, valueResult) Next pair ' Extracting a specific field using a standard operand symbol Console.WriteLine("Source name: {0}", _ e.EventData.FieldResults(UABaseEventObject.Operands.SourceName)) ' Extracting a specific field using an event type ID and a simple relative path Console.WriteLine("Message: {0}", _ e.EventData.FieldResults(UAFilterElements.SimpleAttribute(UAObjectTypeIds.BaseEventType, "/Message"))) End Sub End Class End Namespace
// This example shows how to display all fields of incoming events, or extract specific fields. // // Find all latest examples here : https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html . type THelperMethods15 = class class function ObjectTypeIds_BaseEventType: _UANodeId; static; class function UAFilterElements_SimpleAttribute(TypeId: _UANodeId; simpleRelativeBrowsePathString: string): _UASimpleAttributeOperand; static; class function UABaseEventObject_Operands_SourceName: _UASimpleAttributeOperand; static; class function UABaseEventObject_Operands_Message: _UASimpleAttributeOperand; static; end; type TClientEventHandlers15 = class procedure Client_EventNotification( ASender: TObject; sender: OleVariant; const eventArgs: _EasyUAEventNotificationEventArgs); end; procedure TClientEventHandlers15.Client_EventNotification( ASender: TObject; sender: OleVariant; const eventArgs: _EasyUAEventNotificationEventArgs); var AttributeField: OleVariant; Count: Cardinal; Element: OleVariant; EntryEnumerator: IEnumVARIANT; ValueResult: OleVariant; begin WriteLn; // Display the event if eventArgs.EventData = nil then begin WriteLn(eventArgs.ToString); Exit; end; WriteLn('All fields:'); EntryEnumerator := eventArgs.EventData.FieldResults.GetEnumerator; while (EntryEnumerator.Next(1, Element, Count) = S_OK) do begin AttributeField := IUnknown(Element.Key) as _UAAttributeField; ValueResult := IUnknown(Element.Value) as _ValueResult; WriteLn(' ', AttributeField.ToString, ' -> ', ValueResult.ToString); end; // Extracting specific fields using an event type ID and a simple relative path WriteLn('Source name: ', eventArgs.EventData.FieldResults.Item[THelperMethods15.UABaseEventObject_Operands_SourceName.ToUAAttributeField].ToString); WriteLn('Message: ', eventArgs.EventData.FieldResults.Item[THelperMethods15.UABaseEventObject_Operands_Message.ToUAAttributeField].ToString); end; class procedure FieldResults.Main; const UAObjectIds_Server = 'nsu=http://opcfoundation.org/UA/;i=2253'; var Client: TEasyUAClient; ClientEventHandlers: TClientEventHandlers15; EndpointDescriptor: string; begin EndpointDescriptor := 'opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer'; // Instantiate the client object and hook events Client := TEasyUAClient.Create(nil); ClientEventHandlers := TClientEventHandlers15.Create; Client.OnEventNotification := ClientEventHandlers.Client_EventNotification; WriteLn('Subscribing...'); Client.SubscribeEvent(EndpointDescriptor, UAObjectIds_Server, 1000); WriteLn('Processing event notifications for 30 seconds...'); PumpSleep(30*1000); WriteLn('Unsubscribing...'); Client.UnsubscribeAllMonitoredItems; WriteLn('Waiting for 5 seconds...'); Sleep(5*1000); WriteLn('Finished.'); FreeAndNil(Client); FreeAndNil(ClientEventHandlers); end; // Example output (truncated): //Subscribing... //Processing event notifications for 30 seconds... // //[] Success // ///[] Success; Refresh; RefreshInitiated // //All fields: // NodeId="BaseEventType", NodeId -> Success; nsu=http://opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank?OnlineState {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/EventId -> Success; [16] {95, 68, 22, 205, 114, ...} {System.Byte[]} // NodeId="BaseEventType"/EventType -> Success; DialogConditionType {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/SourceNode -> Success; nsu=http://opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/SourceName -> Success; EastTank {System.String} // NodeId="BaseEventType"/Time -> Success; 9/10/2019 8:08:23 PM {System.DateTime} // NodeId="BaseEventType"/ReceiveTime -> Success; 9/10/2019 8:08:23 PM {System.DateTime} // NodeId="BaseEventType"/LocalTime -> Success; 00:00, DST {OpcLabs.EasyOpc.UA.UATimeZoneData} // NodeId="BaseEventType"/Message -> Success; The dialog was activated {System.String} // NodeId="BaseEventType"/Severity -> Success; 100 {System.Int32} //Source name: Success; EastTank {System.String} //Message: Success; The dialog was activated {System.String} // //All fields: // NodeId="BaseEventType", NodeId -> Success; nsu=http://opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank?Red {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/EventId -> Success; [16] {124, 156, 219, 54, 120, ...} {System.Byte[]} // NodeId="BaseEventType"/EventType -> Success; ExclusiveDeviationAlarmType {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/SourceNode -> Success; nsu=http://opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/SourceName -> Success; EastTank {System.String} // NodeId="BaseEventType"/Time -> Success; 10/14/2019 4:00:13 PM {System.DateTime} // NodeId="BaseEventType"/ReceiveTime -> Success; 10/14/2019 4:00:13 PM {System.DateTime} // NodeId="BaseEventType"/LocalTime -> Success; 00:00, DST {OpcLabs.EasyOpc.UA.UATimeZoneData} // NodeId="BaseEventType"/Message -> Success; The alarm was acknoweledged. {System.String} // NodeId="BaseEventType"/Severity -> Success; 500 {System.Int32} //Source name: Success; EastTank {System.String} //Message: Success; The alarm was acknoweledged. {System.String} // //... class function THelperMethods15.ObjectTypeIds_BaseEventType: _UANodeId; var NodeId: _UANodeId; begin NodeId := CoUANodeId.Create; NodeId.StandardName := 'BaseEventType'; Result := NodeId; end; class function THelperMethods15.UAFilterElements_SimpleAttribute(TypeId: _UANodeId; simpleRelativeBrowsePathString: string): _UASimpleAttributeOperand; var BrowsePathParser: _UABrowsePathParser; Operand: _UASimpleAttributeOperand; begin BrowsePathParser := CoUABrowsePathParser.Create; Operand := CoUASimpleAttributeOperand.Create; Operand.TypeId.NodeId := TypeId; Operand.QualifiedNames := BrowsePathParser.ParseRelative(simpleRelativeBrowsePathString).ToUAQualifiedNameCollection; Result := Operand; end; class function THelperMethods15.UABaseEventObject_Operands_SourceName: _UASimpleAttributeOperand; begin Result := UAFilterElements_SimpleAttribute(ObjectTypeIds_BaseEventType, '/SourceName'); end; class function THelperMethods15.UABaseEventObject_Operands_Message: _UASimpleAttributeOperand; begin Result := UAFilterElements_SimpleAttribute(ObjectTypeIds_BaseEventType, '/Message'); end;
// This example shows how to display all fields of incoming events, or extract specific fields. // // Find all latest examples here : https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html . class ClientEvents { function EventNotification($Sender, $E) { printf("\n"); // Display the event if (is_null($E->EventData)) { printf("%s\n", $E); return; } printf("All fields:\n"); foreach ($E->EventData->FieldResults as $Pair) { $AttributeField = $Pair->Key; $ValueResult = $Pair->Value; printf(" %s -> %s\n", $AttributeField, $ValueResult); } // Extracting specific fields using an event type ID and a simple relative path printf("Source name: %s\n", $E->EventData->FieldResults->Item(UABaseEventObject_Operands_SourceName()->ToUAAttributeField())); printf("Message: %s\n", $E->EventData->FieldResults->Item(UABaseEventObject_Operands_Message()->ToUAAttributeField())); } } const UAObjectIds_Server = "nsu=http://opcfoundation.org/UA/;i=2253"; $EndpointDescriptor = "opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer"; // Instantiate the client object and hook events $Client = new COM("OpcLabs.EasyOpc.UA.EasyUAClient"); $ClientEvents = new ClientEvents(); com_event_sink($Client, $ClientEvents, "DEasyUAClientEvents"); printf("Subscribing...\n"); $Client->SubscribeEvent($EndpointDescriptor, UAObjectIds_Server, 1000); printf("Processing event notifications for 30 seconds...\n"); $startTime = time(); do { com_message_pump(1000); } while (time() < $startTime + 30); printf("Unsubscribing...\n"); $Client->UnsubscribeAllMonitoredItems; printf("Waiting for 5 seconds...\n"); $startTime = time(); do { com_message_pump(1000); } while (time() < $startTime + 5); function ObjectTypeIds_BaseEventType() { $NodeId = new COM("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId"); $NodeId->StandardName = "BaseEventType"; return $NodeId; } function UAFilterElements_SimpleAttribute($TypeId, $simpleRelativeBrowsePathString) { $BrowsePathParser = new COM("OpcLabs.EasyOpc.UA.Navigation.Parsing.UABrowsePathParser"); $Operand = new COM("OpcLabs.EasyOpc.UA.Filtering.UASimpleAttributeOperand"); $Operand->TypeId->NodeId = $TypeId; $Operand->QualifiedNames = $BrowsePathParser->ParseRelative($simpleRelativeBrowsePathString)->ToUAQualifiedNameCollection; return $Operand; } function UABaseEventObject_Operands_SourceName() { return UAFilterElements_SimpleAttribute(ObjectTypeIds_BaseEventType(), "/SourceName"); } function UABaseEventObject_Operands_Message() { return UAFilterElements_SimpleAttribute(ObjectTypeIds_BaseEventType(), "/Message"); } // Example output (truncated): //Subscribing... //Processing event notifications for 30 seconds... // //[] Success // //[] Success; Refresh; RefreshInitiated // //All fields: // NodeId="BaseEventType", NodeId -> Success; nsu=http://opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank?OnlineState {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/EventId -> Success; [16] {95, 68, 22, 205, 114, ...} {System.Byte[]} // NodeId="BaseEventType"/EventType -> Success; DialogConditionType {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/SourceNode -> Success; nsu=http://opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/SourceName -> Success; EastTank {System.String} // NodeId="BaseEventType"/Time -> Success; 9/10/2019 8:08:23 PM {System.DateTime} // NodeId="BaseEventType"/ReceiveTime -> Success; 9/10/2019 8:08:23 PM {System.DateTime} // NodeId="BaseEventType"/LocalTime -> Success; 00:00, DST {OpcLabs.EasyOpc.UA.UATimeZoneData} // NodeId="BaseEventType"/Message -> Success; The dialog was activated {System.String} // NodeId="BaseEventType"/Severity -> Success; 100 {System.Int32} //Source name: Success; EastTank {System.String} //Message: Success; The dialog was activated {System.String} // //All fields: // NodeId="BaseEventType", NodeId -> Success; nsu=http://opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank?Red {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/EventId -> Success; [16] {124, 156, 219, 54, 120, ...} {System.Byte[]} // NodeId="BaseEventType"/EventType -> Success; ExclusiveDeviationAlarmType {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/SourceNode -> Success; nsu=http://opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} // NodeId="BaseEventType"/SourceName -> Success; EastTank {System.String} // NodeId="BaseEventType"/Time -> Success; 10/14/2019 4:00:13 PM {System.DateTime} // NodeId="BaseEventType"/ReceiveTime -> Success; 10/14/2019 4:00:13 PM {System.DateTime} // NodeId="BaseEventType"/LocalTime -> Success; 00:00, DST {OpcLabs.EasyOpc.UA.UATimeZoneData} // NodeId="BaseEventType"/Message -> Success; The alarm was acknoweledged. {System.String} // NodeId="BaseEventType"/Severity -> Success; 500 {System.Int32} //Source name: Success; EastTank {System.String} //Message: Success; The alarm was acknoweledged. {System.String} // //...
Rem This example shows how to display all fields of incoming events, or extract specific fields. Rem Rem Find all latest examples here : https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html . Option Explicit Const uaObjectIds_Server = "nsu=http://opcfoundation.org/UA/;i=2253" Dim endpointDescriptor endpointDescriptor = "opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer" ' Instantiate the client object and hook events Dim Client: Set Client = CreateObject("OpcLabs.EasyOpc.UA.EasyUAClient") WScript.ConnectObject Client, "Client_" WScript.Echo "Subscribing..." Client.SubscribeEvent endpointDescriptor, uaObjectIds_Server, 1000 WScript.Echo "Processing event notifications for 30 seconds..." WScript.Sleep 30*1000 WScript.Echo "Unsubscribing..." Client.UnsubscribeAllMonitoredItems WScript.Echo "Waiting for 5 seconds..." WScript.Sleep 5*1000 Function UAFilterElements_SimpleAttribute(TypeId, simpleRelativeBrowsePathString) Dim BrowsePathParser: Set BrowsePathParser = CreateObject("OpcLabs.EasyOpc.UA.Navigation.Parsing.UABrowsePathParser") Dim QualifiedNames: Set QualifiedNames = BrowsePathParser.ParseRelative(simpleRelativeBrowsePathString).ToUAQualifiedNAmeCollection Dim SimpleAttributeOperand: Set SimpleAttributeOperand = CreateObject("OpcLabs.EasyOpc.UA.Filtering.UASimpleAttributeOperand") Set SimpleAttributeOperand.TypeId.NodeId = TypeId Set SimpleAttributeOperand.QualifiedNames = QualifiedNames Set UAFilterElements_SimpleAttribute = SimpleAttributeOperand End Function Function ObjectTypeIds_BaseEventType Dim NodeId: Set NodeId = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UANodeId") NodeId.StandardName = "BaseEventType" Set ObjectTypeIds_BaseEventType = NodeId End Function Function UABaseEventObject_Operands_Message Set UABaseEventObject_Operands_Message = UAFilterElements_SimpleAttribute(ObjectTypeIds_BaseEventType, "/Message") End Function Function UABaseEventObject_Operands_SourceName Set UABaseEventObject_Operands_SourceName = UAFilterElements_SimpleAttribute(ObjectTypeIds_BaseEventType, "/SourceName") End Function Sub Client_EventNotification(Sender, e) WScript.Echo ' Display the event If e.EventData Is Nothing Then WScript.Echo e Exit Sub End If WScript.Echo "All fields:" Dim Pair: For Each Pair In e.EventData.FieldResults Dim AttributeField: Set AttributeField = Pair.Key Dim ValueResult: Set ValueResult = Pair.Value WScript.Echo " " & AttributeField & " -> " & ValueResult Next ' Extracting specific fields using an event type ID and a simple relative path WScript.Echo "Source name: " & e.EventData.FieldResults.Item(UABaseEventObject_Operands_SourceName.ToUAAttributeField) WScript.Echo "Message: " & e.EventData.FieldResults.Item(UABaseEventObject_Operands_Message.ToUAAttributeField) End Sub ' Example output (truncated): 'Subscribing... 'Processing event notifications for 30 seconds... ' '[] Success ' '[] Success; Refresh; RefreshInitiated ' 'All fields: ' NodeId="BaseEventType", NodeId -> Success; nsu=http://opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank?OnlineState {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} ' NodeId="BaseEventType"/EventId -> Success; [16] {95, 68, 22, 205, 114, ...} {System.Byte[]} ' NodeId="BaseEventType"/EventType -> Success; DialogConditionType {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} ' NodeId="BaseEventType"/SourceNode -> Success; nsu=http://opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} ' NodeId="BaseEventType"/SourceName -> Success; EastTank {System.String} ' NodeId="BaseEventType"/Time -> Success; 9/10/2019 8:08:23 PM {System.DateTime} ' NodeId="BaseEventType"/ReceiveTime -> Success; 9/10/2019 8:08:23 PM {System.DateTime} ' NodeId="BaseEventType"/LocalTime -> Success; 00:00, DST {OpcLabs.EasyOpc.UA.UATimeZoneData} ' NodeId="BaseEventType"/Message -> Success; The dialog was activated {System.String} ' NodeId="BaseEventType"/Severity -> Success; 100 {System.Int32} 'Source name: Success; EastTank {System.String} 'Message: Success; The dialog was activated {System.String} ' 'All fields: ' NodeId="BaseEventType", NodeId -> Success; nsu=http://opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank?Red {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} ' NodeId="BaseEventType"/EventId -> Success; [16] {124, 156, 219, 54, 120, ...} {System.Byte[]} ' NodeId="BaseEventType"/EventType -> Success; ExclusiveDeviationAlarmType {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} ' NodeId="BaseEventType"/SourceNode -> Success; nsu=http://opcfoundation.org/Quickstarts/AlarmCondition ;ns=2;s=1:Colours/EastTank {OpcLabs.EasyOpc.UA.AddressSpace.UANodeId} ' NodeId="BaseEventType"/SourceName -> Success; EastTank {System.String} ' NodeId="BaseEventType"/Time -> Success; 10/14/2019 4:00:13 PM {System.DateTime} ' NodeId="BaseEventType"/ReceiveTime -> Success; 10/14/2019 4:00:13 PM {System.DateTime} ' NodeId="BaseEventType"/LocalTime -> Success; 00:00, DST {OpcLabs.EasyOpc.UA.UATimeZoneData} ' NodeId="BaseEventType"/Message -> Success; The alarm was acknoweledged. {System.String} ' NodeId="BaseEventType"/Severity -> Success; 500 {System.Int32} 'Source name: Success; EastTank {System.String} 'Message: Success; The alarm was acknoweledged. {System.String} ' '...
In order to make access to at least some of these results easier (without having to go through indexing an element in the dictionary), the UAEventData object also contains a BaseEvent property (of UABaseEventObject type). The UABaseEventObject class contains properties that directly correspond to information contained in the base event type (from which all UA events are derived), such as SourceName, Time, Message, Severity, etc. In case of an error related to a particular field, the corresponding property will contain its default value (e.g. an empty string for a Message).
// This example shows how to display specific fields of incoming events that are derived from base event type. // // Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html . using System; using OpcLabs.EasyOpc.UA; using OpcLabs.EasyOpc.UA.AddressSpace.Standard; using OpcLabs.EasyOpc.UA.AlarmsAndConditions; using OpcLabs.EasyOpc.UA.OperationModel; namespace UADocExamples.AlarmsAndConditions { class BaseEvent { public static void Main1() { UAEndpointDescriptor endpointDescriptor = "opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer"; // Instantiate the client object and hook events. var client = new EasyUAClient(); client.EventNotification += client_EventNotification; Console.WriteLine("Subscribing..."); client.SubscribeEvent(endpointDescriptor, UAObjectIds.Server, 1000); Console.WriteLine("Processing event notifications for 30 seconds..."); System.Threading.Thread.Sleep(30 * 1000); Console.WriteLine("Unsubscribing..."); client.UnsubscribeAllMonitoredItems(); Console.WriteLine("Waiting for 5 seconds..."); System.Threading.Thread.Sleep(5 * 1000); Console.WriteLine("Finished."); } static void client_EventNotification(object sender, EasyUAEventNotificationEventArgs e) { Console.WriteLine(); // Display the event. if (e.EventData is null) { Console.WriteLine(e); return; } UABaseEventObject baseEventObject = e.EventData.BaseEvent; Console.WriteLine($"Source name: {baseEventObject.SourceName}"); Console.WriteLine($"Message: {baseEventObject.Message}"); Console.WriteLine($"Severity: {baseEventObject.Severity}"); } } }
# This example shows how to display specific fields of incoming events that are derived from base event type. # # Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html . #requires -Version 5.1 using namespace OpcLabs.EasyOpc.UA using namespace OpcLabs.EasyOpc.UA.AddressSpace using namespace OpcLabs.EasyOpc.UA.AddressSpace.Standard # The path below assumes that the current directory is [ProductDir]/Examples-NET/PowerShell/Windows . Add-Type -Path "../../../Components/Opclabs.QuickOpc/net472/OpcLabs.EasyOpcUA.dll" Add-Type -Path "../../../Components/Opclabs.QuickOpc/net472/OpcLabs.EasyOpcUAComponents.dll" # Define which server we will work with. [UAEndpointDescriptor]$endpointDescriptor = "opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer" # Instantiate the client object. $client = New-Object EasyUAClient # Event notification handler Register-ObjectEvent -InputObject $client -EventName EventNotification -Action { Write-Host # Display the event. if ($EventArgs.EventData -eq $null) { Write-Host $EventArgs return } $baseEventObject = $EventArgs.EventData.BaseEvent Write-Host "Source name: $($baseEventObject.SourceName)" Write-Host "Message: $($baseEventObject.Message)" Write-Host "Severity: $($baseEventObject.Severity)" } Write-Host "Subscribing..." [IEasyUAClientExtension]::SubscribeEvent($client, $endpointDescriptor, [UAObjectIds]::Server, 1000) Write-Host "Processing event notifications for 30 seconds..." $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() while ($stopwatch.Elapsed.TotalSeconds -lt 30) { Start-Sleep -Seconds 1 } Write-Host "Unsubscribing..." $client.UnsubscribeAllMonitoredItems() Write-Host "Waiting for 5 seconds..." Start-Sleep -Seconds 5 Write-Host "Finished."
# This example shows how to display specific fields of incoming events that are derived from base event type. # # Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html . # OPC client and subscriber examples in Python on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-Python . # The QuickOPC package is needed. Install it using "pip install opclabs_quickopc". import opclabs_quickopc import time # Import .NET namespaces. from OpcLabs.EasyOpc.UA import * from OpcLabs.EasyOpc.UA.AddressSpace.Standard import * from OpcLabs.EasyOpc.UA.AlarmsAndConditions import * from OpcLabs.EasyOpc.UA.OperationModel import * def eventNotification(sender, eventArgs): print() # Display the event. if eventArgs.EventData is None: print(eventArgs) return baseEventObject = eventArgs.EventData.BaseEvent print('Source name: ', baseEventObject.SourceName, sep='') print('Message: ', baseEventObject.Message, sep='') print('Severity: ', baseEventObject.Severity, sep='') # Define which server we will work with. endpointDescriptor = UAEndpointDescriptor('opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer') # Instantiate the client object and hook events. client = EasyUAClient() client.EventNotification += eventNotification print('Subscribing...') IEasyUAClientExtension.SubscribeEvent( client, endpointDescriptor, UANodeDescriptor(UAObjectIds.Server), 1000) print('Processing event notifications for 30 seconds...') time.sleep(30) print('Unsubscribing...') client.UnsubscribeAllMonitoredItems() print('Waiting for 5 seconds...') time.sleep(5) print('Finished.')
' This example shows how to display specific fields of incoming events that are derived from base event type. ' ' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html . Imports OpcLabs.EasyOpc.UA Imports OpcLabs.EasyOpc.UA.AddressSpace.Standard Imports OpcLabs.EasyOpc.UA.OperationModel Namespace AlarmsAndConditions Friend Class BaseEvent Public Shared Sub Main1() ' Instantiate the client object and hook events Dim client = New EasyUAClient() AddHandler client.EventNotification, AddressOf client_EventNotification Console.WriteLine("Subscribing...") client.SubscribeEvent( _ "opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer", _ UAObjectIds.Server, _ 1000) Console.WriteLine("Processing event notifications for 30 seconds...") Threading.Thread.Sleep(30 * 1000) Console.WriteLine("Unsubscribing...") client.UnsubscribeAllMonitoredItems() Console.WriteLine("Waiting for 5 seconds...") Threading.Thread.Sleep(5 * 1000) End Sub Private Shared Sub client_EventNotification(ByVal sender As Object, ByVal e As EasyUAEventNotificationEventArgs) Console.WriteLine() ' Display the event If e.EventData Is Nothing Then Console.WriteLine(e) Exit Sub End If Dim baseEventObject = e.EventData.BaseEvent Console.WriteLine("Source name: {0}", baseEventObject.SourceName) Console.WriteLine("Message: {0}", baseEventObject.Message) Console.WriteLine("Severity: {0}", baseEventObject.Severity) End Sub End Class End Namespace
// This example shows how to display specific fields of incoming events that are derived from base event type. // // Find all latest examples here : https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html . type TClientEventHandlers12 = class procedure Client_EventNotification( ASender: TObject; sender: OleVariant; const eventArgs: _EasyUAEventNotificationEventArgs); end; procedure TClientEventHandlers12.Client_EventNotification( ASender: TObject; sender: OleVariant; const eventArgs: _EasyUAEventNotificationEventArgs); var BaseEventObject: _UABaseEventObject; begin WriteLn; // Display the event if eventArgs.EventData = nil then begin WriteLn(eventArgs.ToString); Exit; end; BaseEventObject := eventArgs.EventData.BaseEvent; WriteLn('Source name: ', BaseEventObject.SourceName); WriteLn('Message: ', BaseEventObject.Message); WriteLn('Severity: ', BaseEventObject.Severity); end; class procedure BaseEvent.Main; const UAObjectIds_Server = 'nsu=http://opcfoundation.org/UA/;i=2253'; var Client: TEasyUAClient; ClientEventHandlers: TClientEventHandlers12; EndpointDescriptor: string; begin EndpointDescriptor := 'opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer'; // Instantiate the client object and hook events Client := TEasyUAClient.Create(nil); ClientEventHandlers := TClientEventHandlers12.Create; Client.OnEventNotification := ClientEventHandlers.Client_EventNotification; WriteLn('Subscribing...'); Client.SubscribeEvent(EndpointDescriptor, UAObjectIds_Server, 1000); WriteLn('Processing event notifications for 30 seconds...'); PumpSleep(30*1000); WriteLn('Unsubscribing...'); Client.UnsubscribeAllMonitoredItems; WriteLn('Waiting for 5 seconds...'); Sleep(5*1000); WriteLn('Finished.'); FreeAndNil(Client); FreeAndNil(ClientEventHandlers); end;
// This example shows how to display specific fields of incoming events that are derived from base event type. // // Find all latest examples here : https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html . class ClientEvents { function EventNotification($Sender, $E) { printf("\n"); // Display the event if (is_null($E->EventData)) { printf("%s\n", $E); return; } $BaseEventObject = $E->EventData->BaseEvent; printf("Source name: %s\n", $BaseEventObject->SourceName); printf("Message: %s\n", $BaseEventObject->Message); printf("Severity: %s\n", $BaseEventObject->Severity); } } const UAObjectIds_Server = "nsu=http://opcfoundation.org/UA/;i=2253"; $EndpointDescriptor = "opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer"; // Instantiate the client object and hook events $Client = new COM("OpcLabs.EasyOpc.UA.EasyUAClient"); $ClientEvents = new ClientEvents(); com_event_sink($Client, $ClientEvents, "DEasyUAClientEvents"); printf("Subscribing...\n"); $Client->SubscribeEvent($EndpointDescriptor, UAObjectIds_Server, 1000); printf("Processing event notifications for 30 seconds...\n"); $startTime = time(); do { com_message_pump(1000); } while (time() < $startTime + 30); printf("Unsubscribing...\n"); $Client->UnsubscribeAllMonitoredItems; printf("Waiting for 5 seconds...\n"); $startTime = time(); do { com_message_pump(1000); } while (time() < $startTime + 5);
It should be noted that the FieldResults directory always contains results for the fields you have specified in Select clause of the event filter, but it can contain some additional fields as well. This happens when these fields are necessary for internal processing inside the component. Your code should be able to ignore the results that it has not requested.
Note: Some data returned use complex data types defined by OPC UA, which QuickOPC transforms to its own .NET types. For example, the UATimeZoneData class contains data returned in the UABaseEventObject.LocalTime property (defines the local time that may or may not take daylight saving time into account).
Copyright © 2004-2024 CODE Consulting and Development, s.r.o., Plzen. All rights reserved. Web page: www.opclabs.com
Send Documentation Feedback. Resources: Knowledge Base, Product Downloads. Technical support: Online Forums, FAQ.Missing some example? Ask us for it on our Online Forums! You do not have to own a commercial license in order to use Online Forums, and we reply to every post.